home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr46 / vfwdk.zip / VFWSDK.ZIP / SAMPLES / ICSAMPLE / ICSAMPLE.C < prev    next >
C/C++ Source or Header  |  1993-02-05  |  43KB  |  1,439 lines

  1. /****************************************************************************
  2.  *
  3.  *   icsample.c
  4.  * 
  5.  *   ICSAMPLE is a sample installable compressor for Video for Windows.
  6.  *
  7.  *   Copyright (c) 1991-1993 Microsoft Corporation.  All Rights Reserved.
  8.  *
  9.  *    You have a royalty-free right to use, modify, reproduce and 
  10.  *    distribute the Sample Files (and/or any modified version) in 
  11.  *    any way you find useful, provided that you agree that 
  12.  *    Microsoft has no warranty obligations or liability for any 
  13.  *    Sample Application Files.
  14.  *
  15.  ***************************************************************************/
  16.  
  17. #include <windows.h>
  18. #include <mmsystem.h>
  19. #include <compddk.h>
  20.  
  21. #include "icsample.h"
  22.  
  23. /*****************************************************************************
  24.  *
  25.  * Sample video compressor. This code demonstrates how to implement an
  26.  * installable compressor.
  27.  *
  28.  * The alogorithm we use is very simple:
  29.  * (1)  Keep one out of every 'n' pixels where 'n' is configurable.
  30.  *      Compression is done on a scan-line basis.
  31.  *
  32.  * (2)  For true-color images (16 or 24 bits) give the option of dropping
  33.  *      some of the lower bits.
  34.  *
  35.  ****************************************************************************/
  36.  
  37. typedef BYTE _huge  *HPBYTE ;
  38. typedef WORD _huge  *HPWORD ;
  39. typedef DWORD _huge *HPDWORD ;
  40.  
  41. #define MODNAME         "ICSAMPLE"
  42.  
  43. char    szDescription[] = "Microsoft Sample Compressor";
  44. char    szName[]        = "MS-Samp";
  45. #define FOURCC_SAMP     mmioFOURCC('S','A','M','P')
  46. #define TWOCC_SAMP      aviTWOCC('d', 'c')
  47. #define BI_SAMP         mmioFOURCC('S','m','p','1')
  48. #define VERSION_SAMP    0x00010000      // 1.00
  49.  
  50. extern HANDLE ghModule ;
  51.  
  52.  
  53. /*****************************************************************************
  54.  *
  55.  * DefaultState holds the compression options that will be used if the user
  56.  * compresses an image without configuring us at all first. In the case of
  57.  * the sample compressor, it is the pixel keep ratio.
  58.  *
  59.  ****************************************************************************/
  60.  
  61. ICSTATE DefaultState = {FOURCC_SAMP,2,0};
  62.  
  63. BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, short msg, WORD wParam, LONG lParam);
  64.  
  65. /*****************************************************************************
  66.  *
  67.  * Various macros that are useful when dealing with bitmaps.
  68.  *
  69.  ****************************************************************************/
  70.  
  71. #define ALIGNULONG(i)     ((i+3)&(~3))                  /* ULONG aligned ! */
  72. #define WIDTHBYTES(i)     ((unsigned)((i+31)&(~31))/8)  /* ULONG aligned ! */
  73. #define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  74.  
  75. /*****************************************************************************
  76.  *
  77.  * Function for buffering bits
  78.  *
  79.  ****************************************************************************/
  80.  
  81. typedef struct tagBitBuffer
  82. {
  83.     HPWORD          lpwBuffer ;
  84.     DWORD           dwStored ;
  85.     WORD            wMask ;
  86.     WORD            wFile ;
  87. } BITBUFFER, FAR *LPBITBUFFER ;
  88.  
  89. #define MAX_MASK    (0x8000L)
  90.  
  91. void InitBitBuffer( LPBITBUFFER lpbb,void _huge *lpwBuffer )
  92. {
  93.     /*
  94.     ** Same code is valid for both input and output
  95.     */
  96.     lpbb->lpwBuffer = lpwBuffer ;
  97.     lpbb->dwStored = 0 ;
  98.     lpbb->wMask = MAX_MASK ;
  99.     lpbb->wFile = 0 ;
  100. }
  101.  
  102. void OutputBits( LPBITBUFFER lpbb, WORD wBits, WORD wCount )
  103. {
  104.     WORD    wMask ;
  105.  
  106.     wMask = 1 << (wCount-1) ;
  107.     while (wMask)
  108.     {
  109.         if (wMask&wBits)
  110.             lpbb->wFile |= lpbb->wMask ;
  111.         lpbb->wMask >>= 1 ;
  112.         if ( !lpbb->wMask )
  113.         {
  114.             *lpbb->lpwBuffer++ = lpbb->wFile ;
  115.             lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  116.             lpbb->wFile = 0 ;
  117.             lpbb->wMask = MAX_MASK ;
  118.         }
  119.         wMask >>= 1 ;
  120.     }
  121. }
  122.  
  123. void OutputBitsFlush( LPBITBUFFER lpbb )
  124. {
  125.     if (lpbb->wMask != MAX_MASK)
  126.     {
  127.         *lpbb->lpwBuffer++ = lpbb->wFile ;
  128.         lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  129.     }
  130. }
  131.  
  132. WORD InputBits( LPBITBUFFER lpbb, WORD wCount )
  133. {
  134.     WORD    wMask ;
  135.     WORD    wRet ;
  136.  
  137.     wMask = 1 << (wCount-1) ;
  138.     wRet = 0 ;
  139.     while (wMask)
  140.     {
  141.         if (lpbb->wMask == MAX_MASK)
  142.         {
  143.             lpbb->wFile = *lpbb->lpwBuffer++ ;
  144.             lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  145.         }
  146.         if (lpbb->wFile&lpbb->wMask)
  147.             wRet |= wMask ;
  148.         wMask >>= 1 ;
  149.         lpbb->wMask >>= 1 ;
  150.         if (!lpbb->wMask)
  151.             lpbb->wMask = MAX_MASK ;
  152.     }
  153.  
  154.     return wRet ;
  155. }
  156.  
  157. /*****************************************************************************
  158.  *
  159.  * MyCompress
  160.  *
  161.  * This routine handles the acutal compression of the bitmap. Note:
  162.  *
  163.  * 1) The use of _huge pointers as the bitmaps are likely to exceed 64k.
  164.  *
  165.  * 2) We must set the biCompression field of the output header.
  166.  *
  167.  * 3) We must set the biSizeImage field of the output header.
  168.  *
  169.  * 4) Uncompressed bitmap scan lines are padded out to the next DWORD
  170.  *    boundry.
  171.  *
  172.  ****************************************************************************/
  173. void NEAR PASCAL MyCompress8(
  174.     INSTINFO * pinst,
  175.     LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
  176.     LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
  177. {
  178.     WORD    wRealLineSize ;
  179.     WORD    wLinePad ;
  180.     WORD    wWidth = (WORD)lpbiInput->biWidth ;
  181.     WORD    wHeight = (WORD)lpbiInput->biHeight ;
  182.     WORD    x,y ;
  183.     WORD    wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
  184.  
  185.     DPF("Compress8()");
  186.  
  187.     lpbiOutput->biBitCount    = 8;
  188.     lpbiOutput->biCompression = BI_SAMP;
  189.     lpbiOutput->biSizeImage   = sizeof(WORD)+((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
  190.  
  191.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth) ;
  192.     wLinePad      = wWidth-wRealLineSize ;
  193.  
  194.     *(ICSTATE _huge *)hpOutput = pinst->CurrentState ;
  195.     hpOutput += sizeof(ICSTATE) ;
  196.  
  197.     for (y=0; y<wHeight; y++ )
  198.     {
  199.         for (x=0; x<wWidth; x += wPixRatio)
  200.         {
  201.             *hpOutput++ = *hpInput ;
  202.             hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  203.         }
  204.  
  205.         hpInput += wLinePad ;
  206.     }
  207. }
  208.  
  209. /*****************************************************************************
  210.  *
  211.  * 16/24 bit compression. Same thing; we just deal with a 2 or 3 bytes per pixel
  212.  * instead of a byte.
  213.  *
  214.  * Note that 8-bit pixel values are indices into a palette; 16-bit and
  215.  * about are actual color values. In particular, 16-bit values are
  216.  * stored as:
  217.  *
  218.  * +-+-----+-----+-----+
  219.  * | |  R  |  G  |  B  |
  220.  * +-+-----+-----+-----+
  221.  *  1 1   1
  222.  *  5 4   0 9   5 4   0
  223.  *
  224.  * Bit 15 is unused; each of red, green, and blue get 5 bits of color data
  225.  * (0-31).
  226.  *
  227.  * For 24 bit images, each pixel is three bytes long. The bytes hold
  228.  * the blue, green, and red values respectively (NOTE THE ORDER IS
  229.  * OPPOSITE OF RGB!)
  230.  *
  231.  ****************************************************************************/
  232. void NEAR PASCAL MyCompress16(
  233.     INSTINFO * pinst,
  234.     LPBITMAPINFOHEADER lpbiInput, HPWORD hpInput,
  235.     LPBITMAPINFOHEADER lpbiOutput,HPWORD hpOutput)
  236. {
  237.     WORD        wRealLineSize ;
  238.     WORD        wLinePad ;
  239.     WORD        wWidth = (WORD)lpbiInput->biWidth ;
  240.     WORD        wHeight = (WORD)lpbiInput->biHeight ;
  241.     WORD        x,y ;
  242.     WORD        wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
  243.     WORD        wDropBits = pinst->CurrentState.wColorBitsToDrop ;
  244.     WORD        wKeepBits = 5 - wDropBits ;
  245.     WORD        r,g,b ;
  246.     BITBUFFER   bb ;
  247.  
  248.     DPF("Compress16()") ;
  249.     
  250.     lpbiOutput->biBitCount    = 16;
  251.     lpbiOutput->biCompression = BI_SAMP;
  252.     lpbiOutput->biSizeImage   = sizeof(WORD)+2*((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
  253.  
  254.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*2) ;
  255.     wLinePad      = wWidth*2-wRealLineSize ;
  256.  
  257.     *(ICSTATE _huge *)hpOutput = pinst->CurrentState ;
  258.     hpOutput += sizeof(ICSTATE) ;
  259.  
  260.     InitBitBuffer( &bb,hpOutput ) ;
  261.     
  262.     for (y=0; y<wHeight; y++ )
  263.     {
  264.         for (x=0; x<wWidth; x += wPixRatio)
  265.         {
  266.             r = ((*hpInput>>10)&0x1F)>>wDropBits ;
  267.             g = ((*hpInput>>5)&0x1F)>>wDropBits ;
  268.             b = (*hpInput&0x1F)>>wDropBits ;
  269.             hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  270.  
  271.             OutputBits( &bb, r, wKeepBits ) ;
  272.             OutputBits( &bb, g, wKeepBits ) ;
  273.             OutputBits( &bb, b, wKeepBits ) ; 
  274.         }
  275.  
  276.         hpInput += wLinePad ;
  277.     }
  278.  
  279.     OutputBitsFlush(&bb) ;
  280.  
  281.     lpbiOutput->biSizeImage = sizeof(ICSTATE) + bb.dwStored ;
  282. }   
  283.     
  284. void NEAR PASCAL MyCompress24(
  285.     INSTINFO * pinst,
  286.     LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
  287.     LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
  288. {
  289.     WORD        wRealLineSize ;
  290.     WORD        wLinePad ;
  291.     WORD        wWidth = (WORD)lpbiInput->biWidth ;
  292.     WORD        wHeight = (WORD)lpbiInput->biHeight ;
  293.     WORD        x,y ;
  294.     WORD        wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
  295.     WORD        wDropBits = pinst->CurrentState.wColorBitsToDrop ;
  296.     WORD        wKeepBits = 8 - wDropBits ;
  297.     WORD        r,g,b ;
  298.     BITBUFFER   bb ;
  299.  
  300.     DPF("Compress24()") ;
  301.     
  302.     lpbiOutput->biBitCount    = 24 ;
  303.     lpbiOutput->biCompression = BI_SAMP;
  304.  
  305.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*3) ;
  306.     wLinePad      = wWidth*3-wRealLineSize ;
  307.  
  308.     *(ICSTATE _huge *)hpOutput = pinst->CurrentState ;
  309.     hpOutput += sizeof(ICSTATE) ;
  310.  
  311.     InitBitBuffer( &bb,hpOutput ) ;
  312.     
  313.     for (y=0; y<wHeight; y++ )
  314.     {
  315.         for (x=0; x<wWidth; x += wPixRatio)
  316.         {
  317.             b = (hpInput[0])>>wDropBits ;
  318.             g = (hpInput[1])>>wDropBits ;
  319.             r = (hpInput[2])>>wDropBits ;
  320.             hpInput += 3 * min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  321.  
  322.             OutputBits( &bb, r, wKeepBits ) ;
  323.             OutputBits( &bb, g, wKeepBits ) ;
  324.             OutputBits( &bb, b, wKeepBits ) ; 
  325.         }
  326.  
  327.         hpInput += wLinePad ;
  328.     }
  329.     OutputBitsFlush(&bb) ;
  330.  
  331.     lpbiOutput->biSizeImage = sizeof(ICSTATE) + bb.dwStored ;
  332. }   
  333.     
  334.     
  335. /*****************************************************************************
  336.  *
  337.  * MyDecompress
  338.  *
  339.  * This function is the inverse of MyCompress and follows the same caveats.
  340.  *
  341.  * We shouldn't depend on the state to accurately tell us how to
  342.  * decompress; this info needs to come totally from the compressed data!
  343.  *
  344.  ****************************************************************************/
  345. void NEAR PASCAL MyDecompress8(
  346.     INSTINFO * pinst,
  347.     LPBITMAPINFOHEADER lpbiInput,  HPBYTE hpInput,
  348.     LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput,
  349.     DWORD ckid)
  350. {
  351.     WORD        x,y,xrun ;
  352.     WORD        wRealLineSize ;
  353.     WORD        wLinePad ;
  354.     ICSTATE     icstate ;
  355.     WORD        wWidth = (WORD)lpbiOutput->biWidth ;
  356.     WORD        wHeight = (WORD)lpbiOutput->biHeight ;
  357.  
  358.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth) ;
  359.     wLinePad      = (WORD)wWidth-wRealLineSize ;
  360.  
  361.     icstate = *(ICSTATE _huge *)hpInput ;
  362.     hpInput += sizeof(ICSTATE) ;
  363.  
  364.     for (y=0; y < wHeight; y++)
  365.     {
  366.         for (x=0; x<wWidth; )
  367.         {
  368.             xrun = min(wWidth-x,icstate.wPixelKeepRatio) ;
  369.             x += xrun ;
  370.             while (xrun--)
  371.                 *hpOutput++ = *hpInput ;
  372.  
  373.             hpInput++ ;
  374.         }
  375.  
  376.         hpOutput += wLinePad ;
  377.     }
  378. }
  379.  
  380. void NEAR PASCAL MyDecompress16(
  381.     INSTINFO * pinst,
  382.     LPBITMAPINFOHEADER lpbiInput,  HPWORD hpInput,
  383.     LPBITMAPINFOHEADER lpbiOutput, HPWORD hpOutput,
  384.     DWORD ckid)
  385. {
  386.     WORD        x,y,xrun ;
  387.     WORD        wRealLineSize ;
  388.     WORD        wLinePad ;
  389.     ICSTATE     icstate ;
  390.     WORD        wWidth = (WORD)lpbiOutput->biWidth ;
  391.     WORD        wHeight = (WORD)lpbiOutput->biHeight ;
  392.     WORD        wDropBits ;  
  393.     WORD        wKeepBits ;
  394.     WORD        r,g,b,color ;
  395.     BITBUFFER   bb ;
  396.  
  397.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*2) ;
  398.     wLinePad      = (WORD)wWidth*2-wRealLineSize ;
  399.  
  400.     icstate = *(ICSTATE _huge *)hpInput ;
  401.     hpInput += sizeof(ICSTATE) ;
  402.  
  403.     wDropBits = icstate.wColorBitsToDrop ;
  404.     wKeepBits = 5 - wDropBits ;
  405.  
  406.     InitBitBuffer( &bb, hpInput ) ;
  407.  
  408.     for (y=0; y < wHeight; y++)
  409.     {
  410.         for (x=0; x<wWidth; )
  411.         {
  412.             r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  413.             g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  414.             b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  415.  
  416.             color = (r << 10) | (g << 5) | b ;
  417.             
  418.             xrun = min(wWidth-x,icstate.wPixelKeepRatio) ;
  419.             x += xrun ;
  420.             while (xrun--)
  421.                 *hpOutput++ = color ;
  422.         }
  423.  
  424.         hpOutput += wLinePad ;
  425.     }
  426. }
  427.  
  428. void NEAR PASCAL MyDecompress24(
  429.     INSTINFO * pinst,
  430.     LPBITMAPINFOHEADER lpbiInput,  HPBYTE hpInput,
  431.     LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput,
  432.     DWORD ckid)
  433. {
  434.     WORD        x,y,xrun ;
  435.     WORD        wRealLineSize ;
  436.     WORD        wLinePad ;
  437.     ICSTATE     icstate ;
  438.     WORD        wWidth = (WORD)lpbiOutput->biWidth ;
  439.     WORD        wHeight = (WORD)lpbiOutput->biHeight ;
  440.     WORD        wDropBits ;  
  441.     WORD        wKeepBits ;
  442.     WORD        r,g,b ;
  443.     BITBUFFER   bb ;
  444.  
  445.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*3) ;
  446.     wLinePad      = (WORD)wWidth*3-wRealLineSize ;
  447.  
  448.     icstate = *(ICSTATE _huge *)hpInput ;
  449.     hpInput += sizeof(ICSTATE) ;
  450.  
  451.     wDropBits = icstate.wColorBitsToDrop ;
  452.     wKeepBits = 8 - wDropBits ;
  453.  
  454.     InitBitBuffer( &bb, hpInput ) ;
  455.  
  456.     for (y=0; y < wHeight; y++)
  457.     {
  458.         for (x=0; x<wWidth; )
  459.         {
  460.             r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  461.             g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  462.             b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  463.  
  464.             xrun = min(wWidth-x,icstate.wPixelKeepRatio) ;
  465.             x += xrun ;
  466.             while (xrun--)
  467.             {
  468.                 *hpOutput++ = (BYTE)b ;
  469.                 *hpOutput++ = (BYTE)g ;
  470.                 *hpOutput++ = (BYTE)r ;
  471.             }
  472.         }
  473.  
  474.         hpOutput += wLinePad ;
  475.     }
  476. }
  477.  
  478. /*****************************************************************************
  479.  *
  480.  * Load() is called from the ICM_LOAD message.
  481.  *
  482.  * Tasks such as allocating global memory that is non-instance specific
  483.  * or initializing coprocessor hardware may be performed here.
  484.  *
  485.  * Our simple case needs none of this.
  486.  *
  487.  ****************************************************************************/
  488. BOOL NEAR PASCAL Load(void)
  489. {
  490.     DPF("Load()");
  491.     return TRUE;
  492. }
  493.  
  494. /*****************************************************************************
  495.  *
  496.  * Free() is called from the ICM_FREE message.
  497.  *
  498.  * It should totally reverse the effects of Load() in preparation for
  499.  * the DRV being removed from memory.
  500.  *
  501.  ****************************************************************************/
  502. void NEAR PASCAL Free()
  503. {
  504.     DPF("Free()");
  505. }
  506.  
  507. /*****************************************************************************
  508.  *
  509.  * Open() is called from the ICM_OPEN message
  510.  *
  511.  * This message will be sent for a particular compress/decompress session.
  512.  * Our code must verify that we are indeed being called as a video
  513.  * compressor and create/initialize a state structure. The ICM will
  514.  * give us back the pointer to that structure on every message dealing
  515.  * with this session.
  516.  *
  517.  ****************************************************************************/
  518. INSTINFO * NEAR PASCAL Open(ICOPEN FAR * icinfo)
  519. {
  520.     INSTINFO *  pinst;
  521.  
  522.     DPF("Open('%4.4ls', '%4.4ls')", (LPSTR)&icinfo->fccType, (LPSTR)&icinfo->fccHandler);
  523.  
  524.     //
  525.     // refuse to open if we are not being opened as a Video compressor
  526.     //
  527.     if (icinfo->fccType != ICTYPE_VIDEO)
  528.         return NULL;
  529.  
  530.     pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
  531.  
  532.     if (!pinst)
  533.     {
  534.         icinfo->dwError = ICERR_MEMORY;
  535.         return NULL;
  536.     }
  537.  
  538.     //
  539.     // init structure
  540.     //
  541.     pinst->fccType = ICTYPE_VIDEO;
  542.     pinst->dwFlags = icinfo->dwFlags;
  543.     pinst->nCompress   = 0;
  544.     pinst->nDecompress = 0;
  545.     pinst->nDraw   = 0;
  546.  
  547.     //
  548.     // set the default state.
  549.     //
  550.     SetState(pinst, NULL, 0);
  551.  
  552.     //
  553.     // return success.
  554.     //
  555.     icinfo->dwError = ICERR_OK;
  556.  
  557.     return pinst;
  558. }
  559.  
  560. /*****************************************************************************
  561.  *
  562.  * Close() is called on the ICM_CLOSE message.
  563.  *
  564.  * This message is the complement to ICM_OPEN and marks the end
  565.  * of a compress/decompress session. We kill any in-progress operations
  566.  * (although this shouldn't be needed) and free our instance structure.
  567.  *
  568.  ****************************************************************************/
  569. DWORD NEAR PASCAL Close(INSTINFO * pinst)
  570. {
  571.     DPF("Close()");
  572.  
  573.     while (pinst->nCompress > 0)
  574.         CompressEnd(pinst);
  575.  
  576.     while (pinst->nDecompress > 0)
  577.         DecompressEnd(pinst);
  578.  
  579.     while (pinst->nDraw > 0)
  580.         DrawEnd(pinst);
  581.    
  582.     LocalFree((HLOCAL)pinst);
  583.     
  584.     return 1;
  585. }
  586.  
  587. /*****************************************************************************
  588.  *
  589.  * QueryAbout() and About() handle the ICM_ABOUT message.
  590.  *
  591.  * QueryAbout() returns TRUE to indicate we support an about box.
  592.  * About() displays the box.
  593.  *
  594.  ****************************************************************************/
  595. BOOL NEAR PASCAL QueryAbout(INSTINFO * pinst)
  596. {
  597.     DPF("QueryAbout()");
  598.  
  599.     return TRUE;
  600. }
  601.  
  602. DWORD NEAR PASCAL About(INSTINFO * pinst, HWND hwnd)
  603. {
  604.     DPF("About()");
  605.     MessageBox(hwnd,szDescription,szName,MB_OK|MB_ICONINFORMATION);
  606.     return ICERR_OK;
  607. }
  608.  
  609. /*****************************************************************************
  610.  *
  611.  * QueryConfigure() and Configure() implement the ICM_CONFIGURE message.
  612.  *
  613.  * These functions put up a dialog that allows the user, if he so
  614.  * chooses, to modify the configuration portion of our state info.
  615.  * 
  616.  ****************************************************************************/
  617. BOOL NEAR PASCAL QueryConfigure(INSTINFO * pinst)
  618. {
  619.     DPF("QueryConfigure()");
  620.     return TRUE;
  621. }
  622.  
  623. DWORD NEAR PASCAL Configure(INSTINFO * pinst, HWND hwnd)
  624. {
  625.     DPF("Configure()");
  626.     return DialogBoxParam(ghModule,"Configure",hwnd,ConfigureDlgProc, (LONG)(WORD)pinst);
  627. }
  628.  
  629. /*****************************************************************************
  630.  *
  631.  * GetState() implements the ICM_GETSTATE message.
  632.  * 
  633.  * We copy our configuration information and return how many bytes it took.
  634.  *
  635.  ****************************************************************************/
  636. DWORD NEAR PASCAL GetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
  637. {
  638.     DPF("GetState(%08lX, %ld)", pv, dwSize);
  639.  
  640.     if (pv == NULL || dwSize == 0)
  641.         return sizeof(ICSTATE);
  642.  
  643.     if (dwSize < sizeof(ICSTATE))
  644.         return 0;
  645.  
  646.     *((ICSTATE FAR *)pv) = pinst->CurrentState;
  647.  
  648.     // return number of bytes copied
  649.     return sizeof(ICSTATE);
  650. }
  651.  
  652. /*****************************************************************************
  653.  *
  654.  * SetState() implements the ICM_SETSTATE message.
  655.  *
  656.  * The ICM is giving us configuration information saved by GetState()
  657.  * earlier.
  658.  *
  659.  ****************************************************************************/
  660. DWORD NEAR PASCAL SetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
  661. {
  662.     DPF("SetState(%08lX, %ld)", pv, dwSize);
  663.  
  664.     //
  665.     //  make sure we created this state information.
  666.     //
  667.     if (pv && ((ICSTATE FAR *)pv)->fccHandler != FOURCC_SAMP)
  668.         return 0;
  669.  
  670.     if (pv == NULL)
  671.         pinst->CurrentState = DefaultState;
  672.     else if (dwSize >= sizeof(ICSTATE))
  673.         pinst->CurrentState = *((ICSTATE FAR *)pv);
  674.     else
  675.         return 0;
  676.  
  677.     // return number of bytes copied
  678.     return sizeof(ICSTATE);
  679. }
  680.  
  681. /*****************************************************************************
  682.  *
  683.  * GetInfo() implements the ICM_GETINFO message
  684.  *
  685.  * We just fill in the structure to tell the ICM what we can do. The flags
  686.  * (none of which this sample supports) mean the following :
  687.  *
  688.  * VIDCF_QUALITY - we support the quality variable. This means we look at
  689.  *                 dwQuality in the ICINFO structure when compressing and
  690.  *                 make a concious decision to trade quality for space.
  691.  *                 (higher values of dwQuality mean quality is more
  692.  *                 important). dwQuality is set by the ICM.
  693.  *
  694.  * VIDCF_TEMPORAL - We do interframe compression. In this algorithm, not
  695.  *                  every frame is a "key frame"; some frames depend on
  696.  *                  other frames to be generated. An example of this might
  697.  *                  be to store frame buffer differences until the
  698.  *                  differences are big enough to no longer make this
  699.  *                  worthwhile, then storing another complete frame and
  700.  *                  starting over. In this case, the complete frames that
  701.  *                  are stored are key frames and should be flagged as
  702.  *                  such.
  703.  *
  704.  * VIDCF_DRAW -     We will draw the decompressed image on our own. This is
  705.  *                  useful if the decompression is assisted by the video
  706.  *                  hardware.
  707.  *
  708.  ****************************************************************************/
  709. DWORD NEAR PASCAL GetInfo(INSTINFO * pinst, ICINFO FAR *icinfo, DWORD dwSize)
  710. {
  711.     DPF("GetInfo()");
  712.  
  713.     if (icinfo == NULL)
  714.         return sizeof(ICINFO);
  715.  
  716.     if (dwSize < sizeof(ICINFO))
  717.         return 0;
  718.  
  719.     icinfo->dwSize            = sizeof(ICINFO);
  720.     icinfo->fccType           = ICTYPE_VIDEO;
  721.     icinfo->fccHandler        = FOURCC_SAMP;
  722.     icinfo->dwFlags           = 0;
  723.  
  724.                 //              VIDCF_QUALITY    // supports quality
  725.                 //              VIDCF_TEMPORAL   // supports inter-frame
  726.                 //              VIDCF_DRAW       // supports drawing
  727.  
  728.     icinfo->dwVersion         = VERSION_SAMP;
  729.     icinfo->dwVersionICM      = ICVERSION;
  730.     lstrcpy(icinfo->szDescription, szDescription);
  731.     lstrcpy(icinfo->szName, szName);
  732.  
  733.     return sizeof(ICINFO);
  734. }
  735.  
  736. /*****************************************************************************
  737.  *
  738.  * CompressQuery() handles the ICM_COMPRESSQUERY message
  739.  *
  740.  * This message basically asks, "Can you compress this into this?"
  741.  *
  742.  * We look at the input and output bitmap info headers and determine
  743.  * if we can.
  744.  *
  745.  ****************************************************************************/
  746. LRESULT NEAR PASCAL CompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  747. {
  748.     DPF("CompressQuery()");
  749.  
  750.     //
  751.     // determine if the input DIB data is in a format we like.
  752.     //
  753.     if (lpbiIn == NULL ||
  754.         (lpbiIn->biBitCount != 8 && lpbiIn->biBitCount != 16 && lpbiIn->biBitCount != 24) ||
  755.         lpbiIn->biCompression != BI_RGB)
  756.     {
  757.         return ICERR_BADFORMAT;
  758.     }
  759.  
  760.     //
  761.     //  are we being asked to query just the input format?
  762.     //
  763.     if (lpbiOut == NULL)
  764.         return ICERR_OK;
  765.  
  766.     //
  767.     // make sure we can handle the format to compress to also.
  768.     //
  769.     if (lpbiOut->biCompression != BI_SAMP ||    // must be 'Smp1'
  770.         lpbiOut->biBitCount != lpbiIn->biBitCount ||
  771.         lpbiOut->biWidth  != lpbiIn->biWidth || // must be 1:1 (no stretch)
  772.         lpbiOut->biHeight != lpbiIn->biHeight)
  773.     {
  774.         return ICERR_BADFORMAT;
  775.     }
  776.  
  777.     return ICERR_OK;
  778. }
  779.  
  780. /*****************************************************************************
  781.  *
  782.  * CompressGetFormat() implements ICM_GETFORMAT
  783.  *
  784.  * This message asks, "If I gave you this bitmap, how much memory would it
  785.  * be compressed?"
  786.  *
  787.  * If the output bitmap info header is NULL, we just return how big the
  788.  * header would be (header + palette, actually)
  789.  *
  790.  * Otherwise, we fill in the header, most importantly the biSizeImage.
  791.  * This field must contain an upper bound on the size of the compressed
  792.  * frame. A value that is too high here will result in inefficient
  793.  * memory allocation at compression time, but will not be reflected
  794.  * to the stored bitmap - the compression algorithm may chop biSizeImage
  795.  * down to the actual amount with no ill effects.
  796.  * 
  797.  ****************************************************************************/
  798. LRESULT NEAR PASCAL CompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  799. {
  800.     DWORD dw;
  801.  
  802.     DPF("CompressGetFormat()");
  803.  
  804.     if (dw = CompressQuery(pinst, lpbiIn, NULL))
  805.         return dw;
  806.  
  807.     //
  808.     // if lpbiOut == NULL then, return the size required to hold a output
  809.     // format
  810.     //
  811.     if (lpbiOut == NULL)
  812.         return (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
  813.  
  814.     hmemcpy(lpbiOut, lpbiIn,
  815.         (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  816.  
  817.     lpbiOut->biBitCount    = lpbiIn->biBitCount;
  818.     lpbiOut->biCompression = BI_SAMP;
  819.     lpbiOut->biSizeImage   = CompressGetSize(pinst, lpbiIn, lpbiOut);
  820.  
  821.     return ICERR_OK;
  822. }
  823.  
  824. /*****************************************************************************
  825.  *
  826.  * CompressBegin() implements ICM_COMPRESSBEGIN
  827.  *
  828.  * We're about to start compressing, initialize coprocessor, etc.
  829.  * 
  830.  ****************************************************************************/
  831. LRESULT NEAR PASCAL CompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  832. {
  833.     DWORD dw;
  834.  
  835.     DPF("CompressBegin()");
  836.  
  837.     if (dw = CompressQuery(pinst, lpbiIn, lpbiOut))
  838.         return dw;
  839.  
  840.     if (pinst->nCompress++ > 0)
  841.         return ICERR_OK;
  842.  
  843.     //
  844.     // initialize for compression, for real....
  845.     //
  846.  
  847.     return ICERR_OK;
  848. }
  849.  
  850. /*****************************************************************************
  851.  *
  852.  * CompressGetSize() implements ICM_COMPRESS_GET_SIZE
  853.  *
  854.  * This function returns how much (upper bound) memory a compressed frame
  855.  * will take.
  856.  *
  857.  ****************************************************************************/
  858. LRESULT NEAR PASCAL CompressGetSize(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  859. {
  860.     int dx,dy;
  861.     WORD    wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
  862.     WORD    wPixelSize ;
  863.  
  864.     DPF("CompressGetSize()");
  865.  
  866.     dx = (int)lpbiIn->biWidth;
  867.     dy = (int)lpbiIn->biHeight;
  868.  
  869.     wPixelSize = (lpbiOut->biBitCount+7)/8 ;
  870.  
  871.     return
  872.         sizeof(ICSTATE) +
  873.         wPixelSize*(DWORD)dx*dy ;
  874. }
  875.  
  876. /*****************************************************************************
  877.  *
  878.  * Compress() implements ICM_COMPRESS
  879.  *
  880.  * Everything is set up; call the actual compression routine.
  881.  *
  882.  * Note:
  883.  *
  884.  * 1) We set the ckid in icinfo to a two-character code indicating how we
  885.  *    compressed. This code will be returned to us at decompress time to
  886.  *    allow us to pick a decompression algorithm to match. This is different
  887.  *    from icinfo->fccHandler, which tells which driver to use!
  888.  *
  889.  * 2) We set the key-frame flag on every frame since we do no
  890.  *    temporal (inter-frame) compression.
  891.  *
  892.  ****************************************************************************/
  893. LRESULT NEAR PASCAL Compress(INSTINFO * pinst, ICCOMPRESS FAR *icinfo, DWORD dwSize)
  894. {
  895.     DWORD dw;
  896.  
  897.     DPF("Compress()");
  898.  
  899.     //
  900.     // check for being called without a BEGIN message
  901.     //
  902.     // this should never happen, it is ok to fail this.
  903.     //
  904.     if (pinst->nCompress == 0)
  905.     {
  906.         if (dw = CompressBegin(pinst, icinfo->lpbiInput, icinfo->lpOutput))
  907.             return dw;
  908.     }
  909.  
  910.     if (dw = CompressQuery(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
  911.         return dw;
  912.  
  913.     /* do the compression */
  914.     switch(icinfo->lpbiInput->biBitCount)
  915.     {
  916.         case 8 :
  917.             MyCompress8(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  918.                 icinfo->lpbiOutput, icinfo->lpOutput);
  919.             break ;
  920.  
  921.         case 16 :
  922.             MyCompress16(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  923.                 icinfo->lpbiOutput, icinfo->lpOutput);
  924.             break ;
  925.  
  926.         case 24 :
  927.             MyCompress24(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  928.                 icinfo->lpbiOutput, icinfo->lpOutput);
  929.             break ;
  930.     }
  931.  
  932.     //
  933.     // return the chunk id
  934.     //
  935.     if (icinfo->lpckid)
  936.         *icinfo->lpckid = TWOCC_SAMP;
  937.  
  938.     //
  939.     // set the AVI index flags,
  940.     //
  941.     //    make it a keyframe
  942.     //
  943.     if (icinfo->lpdwFlags)
  944.         *icinfo->lpdwFlags = AVIIF_KEYFRAME;
  945.  
  946.     return ICERR_OK;
  947. }
  948.  
  949. /*****************************************************************************
  950.  *
  951.  * CompressEnd() is called on ICM_COMPRESS_END
  952.  *
  953.  * This function is a chance to flush buffers, deinit hardware, etc.
  954.  * after compressing a single frame.
  955.  *
  956.  ****************************************************************************/
  957. LRESULT NEAR PASCAL CompressEnd(INSTINFO * pinst)
  958. {
  959.     DPF("CompressEnd()");
  960.  
  961.     if (pinst->nCompress == 0)
  962.         return ICERR_ERROR;
  963.  
  964.     if (--pinst->nCompress > 0)
  965.         return ICERR_OK;
  966.  
  967.     /* *** your code here *** */
  968.  
  969.     return ICERR_OK;
  970. }
  971.  
  972. /*****************************************************************************
  973.  *
  974.  * DecompressQuery() implements ICM_DECOMPRESS_QUERY
  975.  *
  976.  * See CompressQuery()
  977.  * 
  978.  ****************************************************************************/
  979. LRESULT NEAR PASCAL DecompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  980. {
  981.     DPF("DecompressQuery()");
  982.  
  983.     //
  984.     // determine if the input DIB data is in a format we like.
  985.     //
  986.     if (lpbiIn == NULL ||
  987.         (lpbiIn->biBitCount != 8 && lpbiIn->biBitCount != 16 && lpbiIn->biBitCount != 24) ||
  988.         lpbiIn->biCompression != BI_SAMP)
  989.     {
  990.         return ICERR_BADFORMAT;
  991.     }
  992.  
  993.     //
  994.     //  are we being asked to query just the input format?
  995.     //
  996.     if (lpbiOut == NULL)
  997.         return ICERR_OK;
  998.  
  999.     //
  1000.     // make sure we can handle the format to compress too.
  1001.     //
  1002.     if (lpbiOut->biCompression != BI_RGB ||         // must be full dib
  1003.         lpbiOut->biBitCount != lpbiIn->biBitCount ||
  1004.         lpbiOut->biWidth  != lpbiIn->biWidth ||     // must be 1:1 (no stretch)
  1005.         lpbiOut->biHeight != lpbiIn->biHeight)
  1006.     {
  1007.         return ICERR_BADFORMAT;
  1008.     }
  1009.  
  1010.     return ICERR_OK;
  1011. }
  1012.  
  1013. /*****************************************************************************
  1014.  *
  1015.  * DecompressGetFormat() implements ICM_DECOMPRESS_GET_FORMAT
  1016.  *
  1017.  * See CompressGetFormat()
  1018.  *
  1019.  ****************************************************************************/
  1020. LRESULT NEAR PASCAL DecompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1021. {
  1022.     DWORD dw;
  1023.     int dx,dy;
  1024.     WORD    wBytesPerPixel ;
  1025.  
  1026.     DPF("DecompressGetFormat()");
  1027.  
  1028.     if (dw = DecompressQuery(pinst, lpbiIn, NULL))
  1029.         return dw;
  1030.  
  1031.     //
  1032.     // if lpbiOut == NULL then, return the size required to hold an output
  1033.     // format
  1034.     //
  1035.     if (lpbiOut == NULL)
  1036.         return (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
  1037.  
  1038.     hmemcpy(lpbiOut, lpbiIn,
  1039.         (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1040.  
  1041.     dx = (int)lpbiIn->biWidth;
  1042.     dy = (int)lpbiIn->biHeight;
  1043.  
  1044.     wBytesPerPixel = (lpbiIn->biBitCount+7)/8 ;
  1045.  
  1046.     lpbiOut->biBitCount    = lpbiIn->biBitCount ; 
  1047.     lpbiOut->biCompression = BI_RGB;
  1048.     lpbiOut->biSizeImage   = wBytesPerPixel*(DWORD)dy*(DWORD)((dx+3)&~3);
  1049.  
  1050.     return ICERR_OK;
  1051. }
  1052.  
  1053. /*****************************************************************************
  1054.  *
  1055.  * DecompressGetPalette() implements ICM_GET_PALETTE
  1056.  *
  1057.  * This function has no Compress...() equivalent
  1058.  *
  1059.  * It is used to pull the palette from a frame in order to possibly do
  1060.  * a palette change.
  1061.  * 
  1062.  ****************************************************************************/
  1063. LRESULT NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1064. {
  1065.     DWORD dw;
  1066.  
  1067.     DPF("DecompressGetPalette()");
  1068.  
  1069.     if (dw = DecompressQuery(pinst, lpbiIn, lpbiOut))
  1070.         return dw;
  1071.  
  1072.     if (lpbiOut->biBitCount != 8)
  1073.         return ICERR_BADFORMAT;
  1074.  
  1075.     //
  1076.     // if you decompress full-color to 8 bit you need to put the "dither"
  1077.     // palette in lpbiOut
  1078.     //
  1079.     if (lpbiIn->biBitCount != 8)
  1080.         return ICERR_BADFORMAT;
  1081.  
  1082.     if (lpbiIn->biClrUsed == 0)
  1083.         lpbiIn->biClrUsed = 256;
  1084.  
  1085.     //
  1086.     // return the 8bit palette used for decompression.
  1087.     //
  1088.     hmemcpy(
  1089.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  1090.         (LPBYTE)lpbiIn + (int)lpbiIn->biSize,
  1091.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1092.  
  1093.     lpbiOut->biClrUsed = lpbiIn->biClrUsed;
  1094.  
  1095.     return ICERR_OK;
  1096. }
  1097.  
  1098. /*****************************************************************************
  1099.  *
  1100.  * DecompressBegin() implements ICM_DECOMPRESS_BEGIN
  1101.  *
  1102.  * See CompressBegin()
  1103.  * 
  1104.  ****************************************************************************/
  1105. LRESULT NEAR PASCAL DecompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1106. {
  1107.     DWORD dw;
  1108.  
  1109.     DPF("DecompressBegin()");
  1110.  
  1111.     if (dw = DecompressQuery(pinst, lpbiIn, lpbiOut))
  1112.         return dw;
  1113.  
  1114.     if (pinst->nDecompress++ > 0)
  1115.         return ICERR_OK;
  1116.  
  1117.     //
  1118.     // start of decompress
  1119.     //
  1120.  
  1121.     return ICERR_OK;
  1122. }
  1123.  
  1124. /*****************************************************************************
  1125.  *
  1126.  * Decompress() implements ICM_DECOMPRESS
  1127.  *
  1128.  * See DecompressBegin()
  1129.  * 
  1130.  ****************************************************************************/
  1131. LRESULT NEAR PASCAL Decompress(INSTINFO * pinst, ICDECOMPRESS FAR *icinfo, DWORD dwSize)
  1132. {
  1133.     DWORD ckid;
  1134.     DWORD dw;
  1135.  
  1136.     DPF("Decompress()");
  1137.  
  1138.     //
  1139.     // check for being called without a BEGIN message
  1140.     //
  1141.     // this should never happen, it is ok to fail this.
  1142.     //
  1143.     if (pinst->nDecompress == 0)
  1144.     {
  1145.         if (dw = DecompressBegin(pinst, icinfo->lpbiInput, icinfo->lpOutput))
  1146.             return dw;
  1147.     }
  1148.  
  1149.     //
  1150.     //  because 'SAMP' frames are key frames we dont need to do any thing if
  1151.     //  behind.
  1152.     //
  1153.     if (icinfo->dwFlags & ICDECOMPRESS_HURRYUP)
  1154.         return ICERR_OK;
  1155.  
  1156.     //
  1157.     // get the chunk id, we realy dont care much about it because we
  1158.     // only have one type of data
  1159.     //
  1160.     ckid = icinfo->ckid;
  1161.  
  1162.     /* do the decompression */
  1163.     switch(icinfo->lpbiInput->biBitCount)
  1164.     {
  1165.         case 8 :
  1166.             MyDecompress8(pinst,icinfo->lpbiInput,  icinfo->lpInput,
  1167.                 icinfo->lpbiOutput, icinfo->lpOutput, ckid);
  1168.             break ;
  1169.  
  1170.         case 16 :
  1171.             MyDecompress16(pinst,icinfo->lpbiInput,  icinfo->lpInput,
  1172.                 icinfo->lpbiOutput, icinfo->lpOutput, ckid);
  1173.             break ;
  1174.  
  1175.         case 24 :
  1176.             MyDecompress24(pinst,icinfo->lpbiInput,  icinfo->lpInput,
  1177.                 icinfo->lpbiOutput, icinfo->lpOutput, ckid);
  1178.             break ;
  1179.  
  1180.     }
  1181.  
  1182.     return ICERR_OK;
  1183. }
  1184.  
  1185. /*****************************************************************************
  1186.  *
  1187.  * DecompressEnd() implements ICM_DECOMPRESS_END
  1188.  *
  1189.  * See CompressEnd()
  1190.  *
  1191.  ****************************************************************************/
  1192. LRESULT NEAR PASCAL DecompressEnd(INSTINFO * pinst)
  1193. {
  1194.     DPF("DecompressEnd()");
  1195.  
  1196.     if (pinst->nDecompress == 0)
  1197.         return ICERR_ERROR;
  1198.  
  1199.     if (--pinst->nDecompress > 0)
  1200.         return ICERR_OK;
  1201.  
  1202.     //
  1203.     // end of decompress.
  1204.     //
  1205.  
  1206.     return ICERR_OK;
  1207. }
  1208.  
  1209. /*****************************************************************************
  1210.  *
  1211.  * DrawQuery() implements ICM_DRAW_QUERY
  1212.  *
  1213.  ****************************************************************************/
  1214. BOOL NEAR PASCAL DrawQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiInput)
  1215. {
  1216.     return FALSE;
  1217. }
  1218.  
  1219. /*****************************************************************************
  1220.  *
  1221.  * DrawBegin() implements ICM_DRAW_BEGIN
  1222.  *
  1223.  * This is just like DecompressBegin() except that we also must prepare to
  1224.  * actually draw the bitmap on the screen. ICDRAWBEGIN provides info specific
  1225.  * to this task.
  1226.  *
  1227.  ****************************************************************************/
  1228. LRESULT NEAR PASCAL DrawBegin(INSTINFO * pinst,ICDRAWBEGIN FAR *icinfo, DWORD dwSize)
  1229. {
  1230.     DPF("DrawBegin()");
  1231.  
  1232.     if (1)  // we dont draw!
  1233.         return ICERR_UNSUPPORTED;
  1234.  
  1235.     if (pinst->nDraw++ > 0)
  1236.         return ICERR_OK;
  1237.  
  1238.     //
  1239.     // but if we did draw we would get ready to draw here
  1240.     //
  1241.  
  1242.     return ICERR_OK;
  1243. }
  1244.  
  1245. /*****************************************************************************
  1246.  *
  1247.  * Draw implements ICM_DRAW
  1248.  *
  1249.  * Decompress and draw
  1250.  *
  1251.  ****************************************************************************/
  1252. LRESULT NEAR PASCAL Draw(INSTINFO * pinst, ICDRAW FAR *icinfo, DWORD dwSize)
  1253. {
  1254.     DPF("Draw()");
  1255.  
  1256.     if (pinst->nDraw == 0)
  1257.         return ICERR_ERROR;
  1258.  
  1259.     return ICERR_UNSUPPORTED;
  1260. }
  1261.  
  1262. /*****************************************************************************
  1263.  *
  1264.  * DrawEnd() implements ICM_DRAW_END
  1265.  *
  1266.  * See DecompressEnd()
  1267.  *
  1268.  ****************************************************************************/
  1269. LRESULT NEAR PASCAL DrawEnd(INSTINFO * pinst)
  1270. {
  1271.     DPF("DrawEnd()");
  1272.  
  1273.     if (1)  // we dont draw!
  1274.         return ICERR_UNSUPPORTED;
  1275.  
  1276.     if (pinst->nDraw == 0)
  1277.         return ICERR_ERROR;
  1278.  
  1279.     if (--pinst->nDraw > 0)
  1280.         return ICERR_OK;
  1281.  
  1282.     //
  1283.     // but if we did we would clean up here
  1284.     //
  1285.  
  1286.     return ICERR_OK;
  1287. }
  1288.  
  1289. /*****************************************************************************
  1290.  *
  1291.  * ConfigureDlgProc() is called by Configure
  1292.  *
  1293.  * This is a standard dialog proc which allows the user to
  1294.  * pick config options for the driver.
  1295.  *
  1296.  ****************************************************************************/
  1297. BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, short msg, WORD wParam, LONG lParam)
  1298. {
  1299.     int             id;
  1300.     static int      s1;
  1301.     static int      s2;
  1302.     HWND            hsb;
  1303.     char            ach[10];
  1304.     
  1305.     static INSTINFO *pinst;
  1306.  
  1307.     #define SCROLL_MIN  1       
  1308.     #define SCROLL_MAX  16      
  1309.  
  1310.     #define SCROLL2_MIN  0       
  1311.     #define SCROLL2_MAX  4      
  1312.  
  1313.         
  1314.     switch (msg)
  1315.     {
  1316.         case WM_COMMAND:
  1317.             switch (wParam)
  1318.             {
  1319.                 case IDOK:
  1320.                     hsb = GetDlgItem(hdlg,ID_SCROLL);
  1321.                     pinst->CurrentState.wPixelKeepRatio = s1 ;
  1322.                     hsb = GetDlgItem(hdlg,ID_SCROLL2);
  1323.                     pinst->CurrentState.wColorBitsToDrop = s2 ;
  1324.                     EndDialog(hdlg,TRUE);
  1325.                     break;
  1326.  
  1327.                 case IDCANCEL:
  1328.                     EndDialog(hdlg,FALSE);
  1329.                     break;
  1330.             }
  1331.             break;
  1332.  
  1333.         case WM_HSCROLL:
  1334.             hsb = (HWND)HIWORD(lParam);
  1335.             id = GetWindowWord(hsb,GWW_ID);
  1336.  
  1337.             switch( id )
  1338.             {
  1339.                 case ID_SCROLL:
  1340.                     s1 = GetScrollPos(hsb,SB_CTL);
  1341.  
  1342.                     switch (wParam)
  1343.                     {
  1344.                         case SB_LINEDOWN:      s1 += 1; break;
  1345.                         case SB_LINEUP:        s1 -= 1; break;
  1346.                         case SB_PAGEDOWN:      s1 += 4; break;
  1347.                         case SB_PAGEUP:        s1 -= 4; break;
  1348.                         case SB_THUMBTRACK:
  1349.                         case SB_THUMBPOSITION: s1 = (int)LOWORD(lParam); break;
  1350.                         default:               return TRUE;
  1351.                     }           
  1352.                 
  1353.                     s1 = max(SCROLL_MIN,min(SCROLL_MAX,s1));
  1354.                     SetScrollPos(hsb,SB_CTL,s1,TRUE);
  1355.                     wsprintf(ach, "%02d", s1);
  1356.                     SetDlgItemText(hdlg,ID_TEXT,ach);
  1357.                     return TRUE;
  1358.  
  1359.                 case ID_SCROLL2:
  1360.                     s2 = GetScrollPos(hsb,SB_CTL);
  1361.  
  1362.                     switch (wParam)
  1363.                     {
  1364.                         case SB_LINEDOWN:      s2 += 1; break;
  1365.                         case SB_LINEUP:        s2 -= 1; break;
  1366.                         case SB_PAGEDOWN:      s2 += 4; break;
  1367.                         case SB_PAGEUP:        s2 -= 4; break;
  1368.                         case SB_THUMBTRACK:
  1369.                         case SB_THUMBPOSITION: s2 = (int)LOWORD(lParam); break;
  1370.                         default:               return TRUE;
  1371.                     }           
  1372.  
  1373.                     s2 = max(SCROLL2_MIN,min(SCROLL2_MAX,s2));
  1374.                     SetScrollPos(hsb,SB_CTL,s2,TRUE);
  1375.                     wsprintf(ach, "%02d", s2);
  1376.                     SetDlgItemText(hdlg,ID_TEXT2,ach);
  1377.                     return TRUE;
  1378.  
  1379.             }
  1380.             return TRUE ;
  1381.  
  1382.  
  1383.         case WM_INITDIALOG:
  1384.             pinst = (INSTINFO *)lParam;
  1385.  
  1386.             hsb = GetDlgItem(hdlg,ID_SCROLL);
  1387.             s1 = pinst->CurrentState.wPixelKeepRatio;
  1388.             SetScrollRange(hsb,SB_CTL,SCROLL_MIN, SCROLL_MAX, TRUE);
  1389.             SetScrollPos(hsb,SB_CTL,s1,TRUE);
  1390.             wsprintf(ach, "%02d", s1);
  1391.             SetDlgItemText(hdlg,ID_TEXT,ach);
  1392.  
  1393.             hsb = GetDlgItem(hdlg,ID_SCROLL2);
  1394.             s2 = pinst->CurrentState.wColorBitsToDrop;
  1395.             SetScrollRange(hsb,SB_CTL,SCROLL2_MIN, SCROLL2_MAX, TRUE);
  1396.             SetScrollPos(hsb,SB_CTL,s2,TRUE);
  1397.             wsprintf(ach, "%02d", s2);
  1398.             SetDlgItemText(hdlg,ID_TEXT2,ach);
  1399.  
  1400.             return TRUE;
  1401.     }
  1402.     return FALSE;
  1403. }
  1404.  
  1405. /*****************************************************************************
  1406.  *
  1407.  * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1408.  *
  1409.  * The messages will be send to COM1: like any debug message. To 
  1410.  * enable debug output, add the following to WIN.INI :
  1411.  *
  1412.  * [debug]
  1413.  * ICSAMPLE=1
  1414.  *
  1415.  ****************************************************************************/
  1416.  
  1417. #ifdef DEBUG
  1418.  
  1419. void FAR cdecl dprintf(LPSTR szFormat, ...)
  1420. {
  1421.     char ach[128];
  1422.  
  1423.     static BOOL fDebug = -1;
  1424.  
  1425.     if (fDebug == -1)
  1426.         fDebug = GetProfileInt("Debug", MODNAME, FALSE);
  1427.  
  1428.     if (!fDebug)
  1429.         return;
  1430.  
  1431.     lstrcpy(ach, MODNAME ": ");
  1432.     wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  1433.     lstrcat(ach, "\r\n");
  1434.  
  1435.     OutputDebugString(ach);
  1436. }
  1437.  
  1438. #endif
  1439.